/*内核模块程序——阻塞IO*/

/*

//add k1																									
key1_button {																									
	compatible = "rk3399,key1-button";																								
	gpios1 = <&gpio1 1 IRQ_TYPE_EDGE_BOTH>; //GPIO1_A1																								
	gpios2 = <&gpio1 3 IRQ_TYPE_EDGE_BOTH>; //GPIO1_A3																								
	gpios3 = <&gpio1 4 IRQ_TYPE_EDGE_BOTH>; //GPIO1_A4																								
	pinctrl-names = "default";																								
	pinctrl-0 = <&button_k1_gpio>;																								
};																									

&pinctrl {																									
	key1_button {																								
		button_k1_gpio:button_k1_gpio {																							
			rockchip,pins = <1 1 RK_FUNC_GPIO &pcfg_pull_up>,																						
			<1 3 RK_FUNC_GPIO &pcfg_pull_up>,																						
			<1 4 RK_FUNC_GPIO &pcfg_pull_up>;																						
		};																							
	};																								
	...																								
};

*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <dt-bindings/gpio/gpio.h>


/*定义结构体类型*/
struct rk3399_button
{
	unsigned int major;
	struct class* pcls;
	struct device* pdev;
	unsigned int gpio1,gpio2,gpio3;//3个引脚号
	int irq1,irq2,irq3;//中断号
	int value;//按键引脚当前电平状态
	int validvalue;//按键引脚有效电平
};

/*全局变量*/
static struct rk3399_button* pbutton;//声明结构体指针，但没分配结构体变量空间

//定义id_table表
static const struct platform_device_id button_id_table[] = 
{
	{ .name = "rk3399_button", .driver_data = 0x1 }, 
	{ .name = "rk3288_button", .driver_data = 0x2 }, 
	{ .name = "rk3568_button", .driver_data = 0x3 },
};

//定义compatible匹配表
static const struct of_device_id button_match[] = 
{
	{ .compatible = "rk3399,key1-button", },
};


/*中断处理函数*/
static irqreturn_t button_handler(int irq, void *dev_id)
{
	int value;
	char* irqdesc = (char*)dev_id;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*判断是哪个按键产生的中断*/
	if(strcmp(irqdesc,"key1") == 0)//如果是key1的中断
	{
		value = gpio_get_value(pbutton->gpio1);
		if(value == pbutton->validvalue)
			printk("<kernel>key1 pressed.\n");
		else
			printk("<kernel>key1 released.\n");
	}
	else if(strcmp(irqdesc,"key2") == 0)//如果是key2的中断
	{
		value = gpio_get_value(pbutton->gpio2);
		if(value == pbutton->validvalue)
			printk("<kernel>key2 pressed.\n");
		else
			printk("<kernel>key2 released.\n");
	}
	else if(strcmp(irqdesc,"key3") == 0)//如果是key3的中断
	{
		value = gpio_get_value(pbutton->gpio3);
		if(value == pbutton->validvalue)
			printk("<kernel>key3 pressed.\n");
		else
			printk("<kernel>key3 released.\n");
	}
	
	return IRQ_HANDLED;
}

/*定义系统调用接口*/


/*定义probe、remove函数*/
static int button_probe(struct platform_device *pdev)
{
	int ret;
	enum of_gpio_flags flags;
	struct device_node* pbutton_node = NULL;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*获取平台数据*/
	pbutton_node = pdev->dev.of_node;

	/*申请分配结构体空间*/
	pbutton = kmalloc(sizeof(struct rk3399_button), GFP_KERNEL);
	if(pbutton == NULL)
	{
		printk("kmalloc fail\n");
		return -ENOMEM;
	}

	/*初始化硬件*/
	pbutton->gpio1 = of_get_named_gpio_flags(pbutton_node, "gpios1", 0, &flags);
	if (gpio_is_valid(pbutton->gpio1)) //如果获取到的引脚号是有效的
	{
		printk("<kernel>Get gpio of key1 success!\n");
		printk("<kernel>gpio of key1 = %d\n", pbutton->gpio1);
	} 
	else 
	{
		printk("<kernel>of_get_named_gpio_flags fail.\n");
		return -EFAULT;
	}
	pbutton->gpio2 = of_get_named_gpio_flags(pbutton_node, "gpios2", 0, &flags);
	if (gpio_is_valid(pbutton->gpio1)) //如果获取到的引脚号是有效的
	{
		printk("<kernel>Get gpio of key1 success!\n");
		printk("<kernel>gpio of key2 = %d\n", pbutton->gpio2);
	} 
	else 
	{
		printk("<kernel>of_get_named_gpio_flags fail.\n");
		return -EFAULT;
	}
	pbutton->gpio3 = of_get_named_gpio_flags(pbutton_node, "gpios3", 0, &flags);
	if (gpio_is_valid(pbutton->gpio1)) //如果获取到的引脚号是有效的
	{
		printk("<kernel>Get gpio of key1 success!\n");
		printk("<kernel>gpio of key3 = %d\n", pbutton->gpio3);
	} 
	else 
	{
		printk("<kernel>of_get_named_gpio_flags fail.\n");
		return -EFAULT;
	}

	/*获取有效电平*/
	if(flags == GPIO_ACTIVE_HIGH)
	{
		printk("<kernel>High is valid.\n");
		pbutton->validvalue = 1;
	}
	else
	{
		printk("<kernel>Low is valid.\n");
		pbutton->validvalue = 0;
	}

	/*设置IO口方向*/
	gpio_request(pbutton->gpio1, "key1");
	gpio_request(pbutton->gpio2, "key2");
	gpio_request(pbutton->gpio3, "key3");
	gpio_direction_input(pbutton->gpio1);//将按键IO口设置为输入方向
	gpio_direction_input(pbutton->gpio2);//将按键IO口设置为输入方向
	gpio_direction_input(pbutton->gpio3);//将按键IO口设置为输入方向
	gpio_free(pbutton->gpio1);
	gpio_free(pbutton->gpio2);
	gpio_free(pbutton->gpio3);

	/*获取中断号*/
	pbutton->irq1 = gpio_to_irq(pbutton->gpio1);
	pbutton->irq2 = gpio_to_irq(pbutton->gpio2);
	pbutton->irq3 = gpio_to_irq(pbutton->gpio3);
	printk("<kernel>irq1:%d\n",pbutton->irq1);
	printk("<kernel>irq2:%d\n",pbutton->irq2);
	printk("<kernel>irq3:%d\n",pbutton->irq3);

	/*申请中断*/
	ret = request_irq(pbutton->irq1, button_handler, IRQ_TYPE_EDGE_BOTH, "k1_interrupt", "key1");
	if (ret) 
	{
		printk("request_irq key1 fail\n");
		return -EFAULT;
	}
	ret = request_irq(pbutton->irq2, button_handler, IRQ_TYPE_EDGE_BOTH, "k2_interrupt", "key2");
	if (ret) 
	{
		printk("request_irq key2 fail\n");
		return -EFAULT;
	}
	ret = request_irq(pbutton->irq3, button_handler, IRQ_TYPE_EDGE_BOTH, "k3_interrupt", "key3");
	if (ret) 
	{
		printk("request_irq key3 fail\n");
		return -EFAULT;
	}

	return 0;
}

static int button_remove(struct platform_device *pdev)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*释放中断*/
	free_irq(pbutton->irq1, "key1");
	free_irq(pbutton->irq2, "key2");
	free_irq(pbutton->irq3, "key3");

	/*释放堆区空间*/
	kfree(pbutton);

	return 0;
}


/*定义平台驱动对象*/	
static struct platform_driver button_driver = 
{
	.probe		= button_probe,
	.remove		= button_remove,
	.driver		= {.name	= "rk_button", .of_match_table = button_match,},
	.id_table	= button_id_table,
};


/*入口函数——insmod调用*/
static int __init driver_mod_init(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return platform_driver_register(&button_driver);
}

/*出口函数——rmmod调用*/
static void __exit driver_mod_exit(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	platform_driver_unregister(&button_driver);
}


module_init(driver_mod_init); //告诉内核本模块程序的入口函数名
module_exit(driver_mod_exit);//告诉内核本模块程序的出口函数名
MODULE_LICENSE("GPL"); //遵守开源许可协议



